/*
 * TMap Designer - A Thematic Map design software
 * Copyright (C) 2006 World Health Organization
 * http://www.who.int
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */
package who.tmap.ui;

import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Frame;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;

import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.BorderFactory;
import javax.swing.DefaultCellEditor;
import javax.swing.InputMap;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JDialog;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.JViewport;
import javax.swing.KeyStroke;
import javax.swing.table.TableCellEditor;
import javax.swing.text.JTextComponent;

import who.tmap.bo.Attrs;
import who.tmap.common.TMapException;
import who.tmap.ui.util.DataUIHelper;
import who.tmap.ui.util.EditDataStructureHelper;
import who.tmap.ui.util.EditDataStructureTableModel;
import who.tmap.ui.util.MiscUIHelper;
import who.tmap.ui.util.jsorttable.CellRenderer;

/**
 * A dialog to edit the data structure
 * (add/remove column(s), edit column name & type
 * 
 * @author stl
 *
 */
public class JDialogEditDataStructure extends JDialog {

	private static final long serialVersionUID = 1L;

	private boolean okPressed =false;
	private Attrs attrs;
	private EditDataStructureHelper edsHelper =new EditDataStructureHelper();
	
	private JPanel jContentPane = null;
	private JPanel jPanelInfos = null;
	private JScrollPane jScrollPane = null;
	private JTable jTable = null;
	private JPanel jPanelInfosButtons = null;
	private JPanel jPanelButtons = null;
	private JButton jButtonOK = null;
	private JButton jButtonCancel = null;
	private JButton jButtonInsertColumn = null;
	private JButton jButtonDeleteColumn = null;

	public JDialogEditDataStructure(Frame owner, Attrs attrs ) {
		super(owner);
		this.attrs =attrs;
		
		initialize();
	}

	private void initialize() {
		this.setSize(400, 300);
		this.setTitle("Edit Data Structure");
		this.setContentPane(getJContentPane());
		this.setLocationRelativeTo( null );
		
		getRootPane().setDefaultButton( getJButtonOK() );
	}

	private JPanel getJContentPane() {
		if (jContentPane == null) {
			jContentPane = new JPanel();
			jContentPane.setLayout(new BorderLayout());
			jContentPane.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
			jContentPane.add(getJPanelInfos(), BorderLayout.CENTER);
			jContentPane.add(getJPanelButtons(), BorderLayout.SOUTH);
		}
		return jContentPane;
	}

	private JPanel getJPanelInfos() {
		if (jPanelInfos == null) {
			jPanelInfos = new JPanel();
			jPanelInfos.setLayout(new BorderLayout());
			jPanelInfos.add(getJScrollPane(), BorderLayout.CENTER);
			jPanelInfos.add(getJPanelInfosButtons(), BorderLayout.SOUTH);
		}
		return jPanelInfos;
	}

	private JScrollPane getJScrollPane() {
		if (jScrollPane == null) {
			jScrollPane = new JScrollPane();
			jScrollPane.setViewportView(getJTable());
		}
		return jScrollPane;
	}

	private JTable getJTable() {
		if (jTable == null) {
			EditDataStructureTableModel tb =new EditDataStructureTableModel();
			tb.setDataStructureColumnInfos( edsHelper.processDscis( attrs.getHeader() ) );
			
			jTable = new JTable( tb )  {
				//  Select the text when the cell starts editing
				//  a) text will be replaced when you start typing in a cell
				//  b) text will be selected when you use F2 to start editing
				//  c) caret is placed at end of text when double clicking to start editing
				public Component prepareEditor(
					TableCellEditor editor, int row, int column)
				{
					Component c = super.prepareEditor(editor, row, column);
	 
					if (c instanceof JTextComponent)
					{
						((JTextField)c).selectAll();
					}
	 
					return c;
				}
			};
			
			CellRenderer cr =new CellRenderer();
			jTable.setDefaultRenderer(Object.class, cr);
			
			InputMap im = jTable.getInputMap(JTable.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
			 
			KeyStroke tab = KeyStroke.getKeyStroke(KeyEvent.VK_TAB, 0);
	 
			final Action oldTabAction = (Action) jTable.getActionMap().get(im.get(tab));
			Action tabAction = new AbstractAction()
			{
				public void actionPerformed(ActionEvent e)
				{
					JTable table = (JTable)e.getSource();
					int originalRow = table.getSelectedRow();
					int originalColumn = table.getSelectedColumn();
					
					oldTabAction.actionPerformed( e );
					
					int row = table.getSelectedRow();
					int column = table.getSelectedColumn();					
	 
					if ( row == 0 && column == 0 ) {
						((EditDataStructureTableModel)table.getModel()).insertRowAt( -1 );
						table.changeSelection(table.getRowCount() -1, 0, false, false);
					} 
				}
			};
			jTable.getActionMap().put(im.get(tab), (javax.swing.Action) tabAction);
			
			KeyStroke enter = KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0);
			final Action oldEnterAction = (Action) jTable.getActionMap().get(im.get(enter));
			Action enterAction = new AbstractAction()
			{
				public void actionPerformed(ActionEvent e)
				{
					JTable table = (JTable)e.getSource();
					int originalRow = table.getSelectedRow();
					int originalColumn = table.getSelectedColumn();
					
					oldEnterAction.actionPerformed( e );
					
					int row = table.getSelectedRow();
					int column = table.getSelectedColumn();					
	 
					if ( row == 0 && (column == originalColumn+1 || ( column == 0 && originalRow == table.getRowCount()-1 ) ) ) {
						((EditDataStructureTableModel)table.getModel()).insertRowAt( -1 );
						table.changeSelection(table.getRowCount() -1, originalColumn, false, false);
					} 
				}
			};
			jTable.getActionMap().put(im.get(enter), (javax.swing.Action) enterAction);
			
			jTable.putClientProperty("terminateEditOnFocusLost", Boolean.TRUE);			
			
			JComboBox cbTypes =new JComboBox( DataUIHelper.AttrTypesUI );
			jTable.getColumnModel().getColumn( EditDataStructureTableModel.TYPE_COL )
				  .setCellEditor( new DefaultCellEditor( cbTypes ) );
		}
		return jTable;
	}

	private JPanel getJPanelInfosButtons() {
		if (jPanelInfosButtons == null) {
			jPanelInfosButtons = new JPanel();
			jPanelInfosButtons.add(getJButtonInsertColumn(), null);
			jPanelInfosButtons.add(getJButtonDeleteColumn(), null);
		}
		return jPanelInfosButtons;
	}

	private JPanel getJPanelButtons() {
		if (jPanelButtons == null) {
			jPanelButtons = new JPanel();
			jPanelButtons.add(getJButtonOK(), null);
			jPanelButtons.add(getJButtonCancel(), null);
		}
		return jPanelButtons;
	}

	private JButton getJButtonOK() {
		if (jButtonOK == null) {
			jButtonOK = new JButton();
			jButtonOK.setText("OK");
			jButtonOK.addActionListener(new java.awt.event.ActionListener() {
				public void actionPerformed(java.awt.event.ActionEvent e) {
					okPressed =true;	
					try {
						edsHelper.processAttrs(attrs, ((EditDataStructureTableModel)getJTable().getModel()).getDataStructureColumnInfos() );
					} catch (TMapException e1) {
						new MiscUIHelper().displayErrorMessage( null, e1 );
					}
					setVisible( false );
				}
			});
		}
		return jButtonOK;
	}

	private JButton getJButtonCancel() {
		if (jButtonCancel == null) {
			jButtonCancel = new JButton();
			jButtonCancel.setText("Cancel");
			jButtonCancel.addActionListener(new java.awt.event.ActionListener() {
				public void actionPerformed(java.awt.event.ActionEvent e) {
					setVisible( false );
				}
			});
		}
		return jButtonCancel;
	}

	public boolean isOkPressed() {
		return okPressed;
	}
	
	public boolean isUpdated() {
		return ((EditDataStructureTableModel)getJTable().getModel()).isDirty();
	}

	private JButton getJButtonInsertColumn() {
		if (jButtonInsertColumn == null) {
			jButtonInsertColumn = new JButton();
			jButtonInsertColumn.setText("Insert");
			jButtonInsertColumn.addActionListener(new java.awt.event.ActionListener() {
				public void actionPerformed(java.awt.event.ActionEvent e) {
					int row =getJTable().getSelectedRow();
					int col =getJTable().getSelectedColumn();
					int newRow =((EditDataStructureTableModel)getJTable().getModel()).insertRowAt( row );
					
					// Make the new row visible (scroll if necessary)
			        JViewport viewport = (JViewport)getJTable().getParent();
			        
			        // This rectangle is relative to the table where the
			        // northwest corner of cell (0,0) is always (0,0).
			        Rectangle rect = getJTable().getCellRect(newRow, col, true);
			    
			        // The location of the viewport relative to the table
			        Point pt = viewport.getViewPosition();
			    
			        // Translate the cell location so that it is relative
			        // to the view, assuming the northwest corner of the
			        // view is (0,0)
			        rect.setLocation( rect.x - pt.x, rect.y - pt.y );
			    
			        // Scroll the area into view
			        viewport.scrollRectToVisible(rect);
			        
			        getJTable().requestFocusInWindow();
					getJTable().changeSelection( newRow, col != -1 ? col : 0, false, false );
						
					Component comp = getJTable().getEditorComponent();
					if ( comp != null ){
						comp.requestFocus();
					}

				}
			});
		}
		return jButtonInsertColumn;
	}

	private JButton getJButtonDeleteColumn() {
		if (jButtonDeleteColumn == null) {
			jButtonDeleteColumn = new JButton();
			jButtonDeleteColumn.setText("Delete");
			jButtonDeleteColumn.addActionListener(new java.awt.event.ActionListener() {
				public void actionPerformed(java.awt.event.ActionEvent e) {
					if ( getJTable().getSelectedRowCount() != 0 ) {
						int row =getJTable().getSelectedRow();
						int col =getJTable().getSelectedColumn();
						
						int[] selectedRows =getJTable().getSelectedRows();
						
						if ( getJTable().isEditing() ) {
							getJTable().getCellEditor().cancelCellEditing();
						}
						
					    ((EditDataStructureTableModel)getJTable().getModel()).removeRows( selectedRows );
					    
					    if ( getJTable().getRowCount() > 0 ) {
					    	if ( row > getJTable().getRowCount()-1 ) {
					    		row--;
					    	}
					    	
					        getJTable().requestFocusInWindow();
							getJTable().changeSelection( row != -1 ? row : 0, col != -1 ? col : 0, false, false );
								
							Component comp = getJTable().getEditorComponent();
							if ( comp != null ){
								comp.requestFocus();
							}
					    }
					}
					
				}
			});
		}
		return jButtonDeleteColumn;
	}	

}
